package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.*;
import com.leyou.item.entity.*;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author YYP
 * @date 2020/12/30
 */
@Service
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    private SpuService spuService;
    @Autowired
    private SpuDetailService spuDetailService;
    @Autowired
    private SkuService skuService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpecParamService specParamService;


    /**
     * 修改库存
     * @param cartsMap
     */
    @Override
    @Transactional
    public void minusStock(Map<Long, Integer> cartsMap) {
        this.skuService.minusStock(cartsMap);
    }

    @Override
    public void listJianStock(Map<String, Long> params) {
        Set<Map.Entry<String, Long>> entries = params.entrySet();
        Iterator<Map.Entry<String, Long>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Long> entry = iterator.next();
            String skuId = entry.getKey();
            Long stock = entry.getValue();

            Sku sku = this.skuService.getById(skuId);
            long oldStock = sku.getStock();
            if (oldStock < stock) {
                throw new LyException(400, "库存不足");
            }
            oldStock = oldStock - stock;
            sku.setStock((int) oldStock);

            this.skuService.updateById(sku);
        }
    }

    /**
     * 根据id查询商品
     *
     * @param spuId
     * @return
     */
    @Override
    public SpuDTO querySpuBySpuId(Long spuId) {
        return new SpuDTO(this.spuService.getById(spuId));
    }

    /**
     * 根据id查询spu及sku、spuDetail等
     *
     * @param spuId
     * @return
     */
    @Override
    public SpuDTO querySpuSkuDetailBySpuId(Long spuId) {
        //查询spu
        Spu spu = this.spuService.query().eq("id", spuId).one();
        SpuDTO spuDTO = new SpuDTO(spu);

        //查询sku
        List<Sku> skuList = this.skuService.query().eq("spu_id", spuId).list();
        List<SkuDTO> skuDTOS = SkuDTO.convertEntityList(skuList);
        //查询detail
        SpuDetail spuDetail = this.spuDetailService.getById(spuId);
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetail);

        spuDTO.setSkus(skuDTOS);
        spuDTO.setSpuDetail(spuDetailDTO);

        return spuDTO;
    }

    /**
     * 根据spuId查询spu的所有规格参数值
     *
     * @param spuId
     * @param searching
     * @return
     */
    //todo
    @Override
    public List<SpecParamDTO> listSpuParamsByQuery(Long spuId, Boolean searching) {
        //根据spuId，查出分类id，
        Spu spu = this.spuService.getById(spuId);
        Long cid3 = spu.getCid3();
        //然后通过分类id，查出规格参数
        List<SpecParamDTO> specParamDTOS = this.specParamService.listParamByQuery(cid3, null, null);

        //从规格参数表中获得的值，没有value，所以我们需要从detail表中获取specification字段
        String specification = this.spuDetailService.getById(spuId).getSpecification();

        //吧规格属性从json转换为map，key为long（规格参数的id），value是规格参数的值
        Map<Long,Object> paramMap = JsonUtils.nativeRead(specification, new TypeReference<Map<Long, Object>>(){});

        for (SpecParamDTO specParamDTO : specParamDTOS) {
            specParamDTO.setValue(paramMap.get(specParamDTO.getId()));
        }


        return specParamDTOS;
    }

    @Override
    public SpuDetailDTO querySpuDetailBySpuId(Long spuId) {
        return new SpuDetailDTO(this.spuDetailService.query().eq("spu_id", spuId).one());
    }

    @Override
    public List<SkuDTO> listSkuBySpuId(Long spuId) {
        return SkuDTO.convertEntityList(this.skuService.query().eq("spu_id", spuId).list());
    }

    /**
     * 根据id批量查询sku
     *
     * @param skuIds
     * @return skuDTOS
     */
    @Override
    public List<SkuDTO> listSkuByIds(List<Long> skuIds) {
        List<Sku> skus = this.skuService.listByIds(skuIds);
        List<SkuDTO> skuDTOS = SkuDTO.convertEntityList(skus);
        return skuDTOS;
    }


    @Autowired
    private AmqpTemplate amqpTemplate;
    /**
     * 修改商品上下架
     *
     * @param id
     * @param saleable update tb_spu set saleable = false where id = #{id}
     */
    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        this.spuService.updateById(spu);

        //修改sku
        skuService.update().eq("spu_id", id).set("saleable", saleable).update();

        //交换机,routingkey,消息(spuId)
        String routingKey = saleable ? "item.up":"item.down";
        this.amqpTemplate.convertAndSend("jhj",routingKey,id);
    }

    /**
     * 更新商品
     *
     * @param spuDTO
     */
    @Override
    public void updateGoods(SpuDTO spuDTO) {
        //如果spu的id不为空，说明有修改的需求
        Long id = spuDTO.getId();
        if (id != null) {
            //更新spu
            Spu spu = spuDTO.toEntity(Spu.class);
            this.spuService.updateById(spu);
        }


        //如果spuDetail不为空说明，有修改的需求
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        if (spuDetailDTO != null) {
            //更新spuDetail
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            //设置spuID
            spuDetail.setSpuId(id);
            this.spuDetailService.updateById(spuDetail);
        }

        //如果sku集合不为空，说明有修改删除，或者新增的需求
        List<SkuDTO> skuDTOS = spuDTO.getSkus();
        if (skuDTOS.size() != 0 && skuDTOS != null) {
            //创建一个map集合，两个实体，key为true则是新增或者修改，false表示要删除
            Map<Boolean, List<Sku>> hashMap;
            hashMap = skuDTOS
                    .stream()
                    .map(skuDTO -> skuDTO.toEntity(Sku.class))
                    .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));


            //如果key为true，新增或者修改
            List<Sku> skuListSaveOrUpdate = hashMap.get(true);
            if (!CollectionUtils.isEmpty(skuListSaveOrUpdate)) {
                this.skuService.saveOrUpdateBatch(skuListSaveOrUpdate);
            }

            List<Sku> skuListDelete = hashMap.get(false);
            if (!CollectionUtils.isEmpty(skuListDelete)) {
                for (Sku sku : skuListDelete) {
                    Long skuId = sku.getId();
                    this.skuService.removeById(skuId);
                }
            }
        }


    }

    /**
     * 新增商品（新增spu，spudetail，sku）
     *
     * @param spuDTO
     * @return
     */
    @Override
    @Transactional
    public void addGoods(SpuDTO spuDTO) {
        //新增商品共有属性spu
        Spu spu = spuDTO.toEntity(Spu.class);
        //boolean save = this.spuService.save(spu);
        spuService.saveSpu(spu);

        //新增商品详细属性
        //spuDetailService.saveSpuDetail(spuDTO);
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        boolean save1 = this.spuDetailService.save(spuDetail);

        //新增商品具体信息sku
        //skuService.saveSku(spuDTO);
        List<SkuDTO> skuDTOS = spuDTO.getSkus();
        for (SkuDTO skuDTO : skuDTOS) {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSpuId(spu.getId());
            this.skuService.save(sku);
        }

    }

    /**
     * 分页查询spu
     *
     * @param page
     * @param rows
     * @param brandId
     * @param categoryId
     * @param id
     * @param saleable
     * @return
     */
    @Override
    public PageDTO<SpuDTO> findSpuByPage(Long page, Long rows, Long brandId, Long categoryId, Long id, Boolean saleable) {
        //分页查询
        QueryWrapper<Spu> wrapper = new QueryWrapper<>();
        wrapper.eq(null != brandId, "brand_id", brandId)
                .eq(null != categoryId, "cid3", categoryId)
                .eq(null != id, "id", id)
                .eq(null != saleable, "saleable", saleable);

        Page<Spu> resultPage = this.spuService.page(new Page<>(page, rows), wrapper);


        //获取items，转换为Dto
        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(resultPage.getRecords());
        //循环给dto赋值，brandName以及categoryName
        for (SpuDTO spuDTO : spuDTOS) {
            //将品牌名，填充到spuDTO中
            spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());
            //TODO 考虑缓存问题，
            //根据分类的id集合查询分类集合，并取出每个分类的名称，并拼接字符串
            List<Category> categories = this.categoryService.listByIds(spuDTO.getCategoryIds());
            String names = categories.stream().map(Category::getName)
                    .collect(Collectors.joining("/"));
            //StringUtils.join(array,分隔符)
            spuDTO.setCategoryName(names);

        }

        return new PageDTO<SpuDTO>(resultPage.getTotal(), resultPage.getPages(), spuDTOS);
    }
}
